package com.example.verticles;

import com.example.constant.Constants;
import com.example.entity.Todo;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.DecodeException;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.redis.client.*;
import io.vertx.redis.client.impl.RedisClient;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class SingleApplicationVerticle extends AbstractVerticle {

  private static final String HTTP_HOST = "127.0.0.1";
  private static final String REDIS_HOST = "101.133.174.208";
  private static final int HTTP_PORT = 8082;
  private static final int REDIS_PORT = 6379;

  private RedisAPI redis;
  @Override
  public void start(Promise<Void> promise) throws Exception {
    initData();
    Router router = Router.router(vertx); // <1>
    // CORS support
    Set<String> allowHeaders = new HashSet<>();
    allowHeaders.add("x-requested-with");
    allowHeaders.add("Access-Control-Allow-Origin");
    allowHeaders.add("origin");
    allowHeaders.add("Content-Type");
    allowHeaders.add("accept");
    Set<HttpMethod> allowMethods = new HashSet<>();
    allowMethods.add(HttpMethod.GET);
    allowMethods.add(HttpMethod.POST);
    allowMethods.add(HttpMethod.DELETE);
    allowMethods.add(HttpMethod.PATCH);

    router.route().handler(CorsHandler.create("*") // <2>
            .allowedHeaders(allowHeaders)
            .allowedMethods(allowMethods));
    router.route().handler(BodyHandler.create()); // <3>

    router.get(Constants.API_GET).handler(this::handleGetTodo);
    router.get(Constants.API_LIST_ALL).handler(this::handleGetAll);
    router.post(Constants.API_CREATE).handler(this::handleCreateTodo);
    router.patch(Constants.API_UPDATE).handler(this::handleUpdateTodo);
    router.delete(Constants.API_DELETE).handler(this::handleDeleteOne);
    router.delete(Constants.API_DELETE_ALL).handler(this::handleDeleteAll);
    vertx.createHttpServer() // <4>
            .requestHandler(httpServerRequest -> {
              router.handle(httpServerRequest);
            })
            .listen(HTTP_PORT, HTTP_HOST, result -> {
              if (result.succeeded())
                promise.complete();
              else
                promise.fail(result.cause());
            });

  }

  private void handleDeleteAll(RoutingContext routingContext) {

  }

  private void handleDeleteOne(RoutingContext routingContext) {

  }

  private void handleUpdateTodo(RoutingContext routingContext) {

  }

  private void handleCreateTodo(RoutingContext routingContext) {
    try {
      System.out.println("====================1");
      final Todo todo = wrapObject(routingContext.body().asJsonObject().mapTo(Todo.class), routingContext);
      final String encoded = todo.toString();
      System.out.println("====================2");
      redis.hset(Arrays.asList(Constants.REDIS_TODO_KEY, String.valueOf(todo.getId()),encoded),
              res->{
                if (res.succeeded())
                  routingContext.response()
                          .setStatusCode(201)
                          .putHeader("content-type", "application/json")
                          .end(encoded);
                else
                  sendError(503, routingContext.response());
              });
    } catch (DecodeException e) {
      sendError(400, routingContext.response());
    }
  }

  private void handleGetAll(RoutingContext routingContext) {

  }

  private void handleGetTodo(RoutingContext routingContext) {

  }

  private Todo wrapObject(Todo todo, RoutingContext context) {
    int id = todo.getId();
    if (id > Todo.getIncId()) {
      Todo.setIncIdWith(id);
    } else if (id == 0)
      todo.setIncId();
    todo.setUrl(context.request().absoluteURI() + "/" + todo.getId());
    return todo;
  }
  private void sendError(int statusCode, HttpServerResponse response) {
    response.setStatusCode(statusCode).end();
  }

  private void initData() {
    RedisOptions config = new RedisOptions()
            .setEndpoints(Arrays.asList("redis://"+REDIS_HOST+":"+REDIS_PORT));
//    RedisClient client= new RedisClient(vertx, config);

    Redis client = Redis.createClient(vertx, config);
    client.connect().onSuccess(conn->{
      System.out.println("conn success");
      conn.send(Request.cmd(Command.INFO))
              .onSuccess(info -> {
                // do something...
                System.out.println(info);
              });
    }).onFailure(
            throwable -> {
              System.err.println("[Error] Redis service is not running!");
              throwable.printStackTrace();
            }
    );
    redis=RedisAPI.api(client);
    redis.get("as").onSuccess(value -> {
      System.out.println("======================"+value);
    });
    redis.setnx("bb","dfd");
    Todo todo = new Todo(24, "Something to do...", false, 1, "todo/ex");
    String s = todo.toString();
    System.out.println(s);
    redis.hset(Arrays.asList(Constants.REDIS_TODO_KEY, "24", s),
            res->{
              if (res.failed()){
                  System.err.println("[Error] Redis service is not running!");
                 res.cause().printStackTrace();
              }else {
                System.out.println("============success===============");
              }
            });


  }
}